# -*- coding: utf-8 -*-
# time: 2025/5/13 11:47
# file: langchain文本分类.py
# author: hanson
"""
langchain提取结构化的数据，提前数据比较智能。
"""
from typing import Optional, List

from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnablePassthrough
from langchain_ollama import ChatOllama
from pydantic import BaseModel, Field
from srsly.util import JSONOutput

# temperature 是一个关键参数，用于控制模型生成文本的 随机性和创造性。以下是它的具体作用：
# temperature 值越高，生成的文本越随机、多样化（可能更创造性，但也更不稳定）。
# temperature 值越低，生成的文本越保守、确定（更接近概率最高的选择，更可预测）
"""
值范围	效果	适用场景
0.1~0.3	输出非常保守，重复性高，适合事实性回答（如问答、代码生成）。	技术文档、精确指令执行。
0.4~0.7	平衡随机性和确定性（你用的 0.5 是常用值），适合一般对话和创意任务。	聊天机器人、内容润色。
0.8~1.0+	输出高度随机，可能不连贯，适合需要创造力的场景（如写诗、故事生成）。	文学创作、头脑风暴。
"""
llm = ChatOllama(model="qwen2.5:1.5b", temperature=0.5)
prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个计算专家"),
    ("user", "{input}")
])
chain = prompt | llm
result = chain.invoke({"input": "299834/889=？"})
print(result.content)

prompt = ChatPromptTemplate.from_messages([
    ("system", "你是一个专业的提取文本的模型，请根据输入的文本内容，提取出结构化数据，并返回。如果值为空返回null"),
    ("user", "{input}")
])

# pydantic  数据结构 处理，验证，类型转换等
# Optional[str] 表示该字段可以为空，str表示该字段的类型为字符串
# 帮助我们从文本中提取出结构化数据
class Person(BaseModel):
    name: Optional[str] = Field(default=None, description="表示人的姓名")
    age: Optional[int] = Field(default=None, description="表示人的年龄")


class MorePerson(BaseModel):
    person: List[Person]

# with_structured_output 模型的输出是结构化的数据，而不是纯文本
chain = {"input": RunnablePassthrough()} | prompt | llm.with_structured_output(schema=Person)

result = chain.invoke({"input": "我的名字是王天霸，年龄是18岁"})

print(result) # 得到 name='张三' age=18

chain = {"input": RunnablePassthrough()} | prompt | llm.with_structured_output(schema=MorePerson)
result = chain.invoke({"input": "我的名字是张天雷，年龄是18岁;王天霸是一个学生，年龄20,"})

print(result) #

